import datetime
import os
from uuid import uuid4

from django.conf import settings
from django.core.cache import cache
from django.db.models import F, Q
from django.shortcuts import render, get_object_or_404
from django.template.loader import render_to_string
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.cache import cache_page
from django.views.generic import DetailView, ListView
from django.core.paginator import Paginator

from utils.response import response, RET
from .models import Article, Comment, ArticleUp, Diary, Friend, Message, Category


class IndexView(View):
    # @method_decorator(cache_page(60 * 60 * 24 * 1, cache='page'))
    def get(self, request):
        return render(request, 'index.html')


class ArticleListView(ListView):
    queryset = Article.objects.order_by('-top', '-update_time')
    template_name = 'article.html'
    paginate_by = settings.ARTICLE_LIST_COUNT
    kw = None

    def get_context_data(self):
        context = super(ArticleListView, self).get_context_data()
        hot_articles = self.queryset.order_by('-up_count')
        top_articles = self.queryset.filter(top=True).order_by('-update_time')
        context.update({
            "blog_category_id": self.kwargs.get('category_id', 0),
            "hot_articles": hot_articles[0:settings.SIDE_ARTICLE_COUNT],
            "top_articles": top_articles[0:settings.SIDE_ARTICLE_COUNT],
            "kw": self.kw,
        })
        return context


class SearchListView(ArticleListView):
    def get_queryset(self):
        self.kw = search = self.request.GET.get('q').strip()
        object_list = self.queryset.filter(Q(title__contains=search) |
                                           Q(content__contains=search))
        return object_list


class ArticleListByCategoryView(ArticleListView):
    def get_queryset(self):
        category_id = self.kwargs.get('category_id')
        category = get_object_or_404(Category, pk=category_id)
        object_list = self.queryset.filter(category=category)
        self.kw = category.name
        return object_list


class ArticleDetailView(DetailView):
    queryset = Article.objects.all()
    template_name = 'read.html'
    comment_page_limit = settings.COMMENT_PAGE_LIMIT

    def get_context_data(self, **kwargs):
        context = super(ArticleDetailView, self).get_context_data(**kwargs)
        # 更新view_count
        if not self.request.session.get(self.request.path, ''):
            context['object'].update_view_count()
            self.request.session[self.request.path] = self.request.path
        # 评论
        comments = Comment.objects.filter(article=context['object'], parent=None).order_by('-create_time')
        paginator = Paginator(comments, self.comment_page_limit)
        context['page_count'] = paginator.num_pages

        return context


class ArticleUpView(View):
    def post(self, request):
        id = request.POST.get('article')
        if not id:
            return response(error=RET.NODATA, message='该文章不存在')
        try:
            article = Article.objects.get(pk=id)
        except Article.DoesNotExist:
            return response(error=RET.NODATA, message='该文章不存在')

        up, created = ArticleUp.objects.get_or_create(user=request.user, article_id=id)
        if not created:
            return response(error=RET.DATAEXIST, message='您已经赞过啦')

        article.update_up_count()
        return response(data=article.up_count)


class ArticleCommentPubView(View):
    def post(self, request):

        content = request.POST.get('content')
        article = request.POST.get('article')
        parent = request.POST.get('parent')
        try:
            article = Article.objects.get(pk=article)
        except Article.DoesNotExist:
            return response(error=RET.NODATA, message='该文章不存在')

        if not content:
            return response(error=RET.DATAERR)
        data = {
            "content": content,
            "article": article,
            "user": request.user,
        }
        if parent:
            if not parent.isdigit():
                return response(error=RET.PARAMERR)
            try:
                comment = Comment.objects.get(pk=parent)

                if request.user == comment.user:
                    return response(error=RET.PARAMERR, message='不能给自己评论')

                data.update({"parent": comment})
            except Comment.DoesNotExist:
                return response(error=RET.NODATA, message='该评论不存在')

        comment = Comment.objects.create(**data)
        article.update_comment_count()
        html = render_to_string('common/comment-pub.html', context={
            "object": comment,
            "article": article,
        })
        return response(message='评论成功', data=html)


class ArticleCommentListView(View):
    comment_page_limit = 10

    def get_children_comment(self, comment, _children):
        comments = comment.get_children
        for item in comments:
            data = item.serializer()
            # 添加盖条评论
            _children.append(data)
            # 该评论有子级 就继续添加
            if item.get_children:
                self.get_children_comment(item, _children)

    def build_tree_comments(self, comments):
        return_list = []
        for comment in comments:
            comment_data = comment.serializer()
            children_data_list = []
            self.get_children_comment(comment, children_data_list)
            comment_data.update({
                "children": children_data_list
            })
            return_list.append(comment_data)
        return return_list

    def get(self, request):
        page = request.GET.get('page', 1)
        article = request.GET.get('article')
        try:
            article = Article.objects.get(pk=article)
            page = int(page)
        except Article.DoesNotExist:
            return response(RET.PARAMERR)
        db_comments = Comment.objects.filter(article=article, parent=None).order_by('-create_time')
        paginator = Paginator(db_comments, self.comment_page_limit)
        page_obj = paginator.page(page)
        comment_data = self.build_tree_comments(page_obj.object_list)
        return render(request, 'common/comment.html', context={
            "comments": comment_data,
            "article": article,
        })


class DiaryView(View):
    def get(self, request):
        diaries = Diary.objects.order_by('-create_time')
        data = {}
        for diary in diaries:
            year = diary.get_year
            if not data.get(year):
                data[year] = []
            data[year].append(diary.serializer())
        return render(request, 'timeline.html', context={
            "data": data
        })


class LinkView(View):
    def get(self, request):
        links = Friend.objects.all()
        return render(request, 'link.html', context={
            "data": links
        })


class AboutView(View):
    def get(self, request):
        return render(request, 'about.html')


class MessageView(View):

    def get(self, request):
        messages = []
        if request.user.is_authenticated:
            db_messages = Message.objects.filter(user=request.user, parent=None).order_by('-create_time')
            for message in db_messages:
                data = message.serializer()
                reply = Message.objects.filter(parent=message.nid).order_by('create_time')
                data.update({
                    "reply": [item.serializer() for item in reply]
                })
                messages.append(data)
        return render(request, 'message.html', {
            "messages": messages,
        })

    def post(self, request):
        content = request.POST.get('content')
        if not content:
            return response(error=RET.PARAMERR, message="请输入内容")
        message = Message.objects.create(content=content, user=request.user)

        return response(data=message.serializer())


class ArchiveView(View):
    def get(self, request):
        articles = Article.objects.order_by('-update_time')

        return render(request, 'archive.html', {
            "articles": articles
        })


class UploadView(View):

    def save_path(self):
        _, ext = self.file.name.rsplit('.', 1)
        uname = uuid4().hex
        time_dir = datetime.datetime.now().strftime('%Y/%m/%d')

        show_dir = os.path.join('/media', *time_dir.split('/'))
        save_dir = os.path.join(settings.MEDIA_ROOT, *time_dir.split('/'))
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)

        return f'{save_dir}/{uname}.{ext}', f'{show_dir}/{uname}.{ext}'.replace('\\', '/')

    def post(self, request):
        self.file = file = request.FILES.get('file')
        # if not re.match(r'image', file.content_type, re.I):
        #     return response(RET.DATAERR, message='请上传图片')
        save_path, show_path = self.save_path()
        with open(save_path, 'wb') as destination:
            for chunk in file.chunks():
                destination.write(chunk)
        # return response(location=show_path)
        return response(location=show_path, data={
            "text": file.name,
        })
